package cn.buk.tms.car.service;

import cn.buk.common.JsonResult;
import cn.buk.qms.service.BaseOrderService;
import cn.buk.tms.car.dto.CarOrderDto;
import cn.buk.tms.car.dto.CarOrderRequestDto;
import cn.buk.tms.car.sc.SearchCarOrderCriteria;
import cn.buk.tms.common.constant.TmsOrderConstant;
import cn.buk.tms.dto.LoginInfoDto;
import cn.buk.tms.entity.bill.BillInfo;
import cn.buk.tms.entity.misc.*;
import cn.buk.tms.util.ValidationUtils;
import cn.buk.common.util.DateUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static cn.buk.tms.common.constant.TmsOrderConstant.RENTAL_CAR_ORDER_STATUS_DONE;
import static cn.buk.tms.common.constant.TmsOrderConstant.RENTAL_CAR_ORDER_STATUS_WAITING;

/**
 * 租车功能服务类
 * @author yfdai
 */
@Component
public class RentalCarServiceImpl extends BaseOrderService implements RentalCarService {

  private static final Logger logger = LogManager.getLogger(RentalCarServiceImpl.class);

  @Autowired
  public RentalCarServiceImpl() {
    //需要用到的dao对象都在基类中有了
  }


  @Override
  public JsonResult createRentalCarOrder(final int enterpriseId, final String username, final CarOrderRequestDto dto) {
    try {
      ValidationUtils.validate(dto);
    } catch (Exception ex) {
      logger.error(ex.getMessage());
      return JsonResult.createJsonResult(-1, ex.getMessage());
    }

    RentalCarOrder orderInfo = new RentalCarOrder();
    BeanUtils.copyProperties(dto, orderInfo);

    orderInfo.setName(dto.getLinkman());
    orderInfo.setMobile(dto.getLinkPhone());

    orderInfo.setEnterpriseId(enterpriseId);
    orderInfo.setOperator(username);

    try {
      Date useDateTime = DateUtil.convertToDate(dto.getUseDate() + " " + dto.getUseTime(), "yyyy-MM-dd HH:mm");
      orderInfo.setUseTime(useDateTime);
    } catch (ParseException e) {
      return JsonResult.createJsonResult(-2, "用车日期和时间转化错误");
    }

    orderInfo.setCityName(dto.getCityName());

    if (dto.getCustomerId() <= 0) {
      orderInfo.setCustomerType(0);
    } else {
      orderInfo.setCustomerType(1);
      Customer c = new Customer();
      c.setId(dto.getCustomerId());
      orderInfo.setCustomer(c);
    }

    if (dto.getSupplierId() > 0) {
      Supplier supplier = new Supplier();
      supplier.setId(dto.getSupplierId());
      orderInfo.setSupplier(supplier);
    }

    if (dto.getPaymentMethodId() > 0) {
      PaymentMethod pm = new PaymentMethod();
      pm.setId(dto.getPaymentMethodId());

      orderInfo.setPaymentMethod(pm);
    }


    //订单号
    orderInfo.setOrderNo(orderNoGenerator.generateOrderNo(enterpriseId, TmsOrderConstant.ORDER_NO_RENTAL_CAR));

    //后台生成的订单默认为 待处理状态
    orderInfo.setStatus(RENTAL_CAR_ORDER_STATUS_WAITING);

    VehicleGroupInfo vehicleGroupInfo = enterpriseDao.getVehicleGroupInfoById(dto.getVehicleTypeId());
    if (vehicleGroupInfo == null) {
      return JsonResult.createJsonResult(-3, "车型信息不存在");
    }

    orderInfo.setVehicleTypeName(vehicleGroupInfo.getName());


    try {
      int retCode = carOrderDao.createCarOrder(orderInfo);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      logger.error(ex.getMessage());
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  public List<CarOrderDto> searchRentalCarOrders(final int enterpriseId, SearchCarOrderCriteria sc) {

    List<RentalCarOrder> orders = carOrderDao.searchOrders(enterpriseId, sc);

    List<CarOrderDto> dtos = new ArrayList<>();

    for (RentalCarOrder order : orders) {
      CarOrderDto dto = CarOrderDto.createByRentalCarOrder(order);
      dtos.add(dto);
    }

    return dtos;
  }

  @Override
  public CarOrderDto searchRentalCarOrder(final int enterpriseId, final int orderId) {
    RentalCarOrder order = carOrderDao.getOrderById(orderId);

    if (order == null || order.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("RentalCar order(" + orderId + ") is not existed.");
    }

    CarOrderDto dto = CarOrderDto.createByRentalCarOrder(order);
    dto.setErrcode(0);
    return dto;
  }

  @Override
  public JsonResult cancelRentalCarOrder(int enterpriseId, String username, int orderId) {
    //TODO 取消时需要判断是否已收款，是否需要退款
    return JsonResult.createJsonResult(
            carOrderDao.cancelRentalCarOrder(enterpriseId, username, orderId));
  }

  @Override
  public List<OperationLog> searchRentalCarOrderHistory(int enterpriseId, int orderId) {
    return carOrderDao.searchHistory(enterpriseId, orderId);
  }

  @Override
  public JsonResult updateRentalOrderPrice(int enterpriseId, String username, int orderId, double price, double discount, double cost) {
    int retCode = carOrderDao
            .updateRentalCarOrderPrice(enterpriseId, username, orderId, price, discount, cost);
    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public JsonResult updateRentalCarOrderSupplier(int enterpriseId, String username, int orderId, int supplierId, int paymentMethodId) {
    try {
      int retCode = carOrderDao.updateRentalCarOrderSupplier(enterpriseId, username, orderId, supplierId, paymentMethodId);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  public JsonResult updateRentalCarOrderPaymentMethod(int enterpriseId, String username, int orderId, int paymentMethodId) {
    try {
      int retCode = carOrderDao.updateRentalCarOrderPaymentMethod(enterpriseId, username, orderId, paymentMethodId);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  public JsonResult processRentalCarOrder(final int enterpriseId, final String username, final int orderId) {
    //核对信用额度是否足够
    RentalCarOrder orderInfo = carOrderDao.getOrderById(orderId);
    if (orderInfo == null || orderInfo.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-404, "不存在");
    }

    if (orderInfo.getCustomer() != null && orderInfo.getCustomer().getCustomerEnterpriseId() > 0) {
      //该客户可以判断授信额度
      final double totalAmount = orderInfo.getPrice() - orderInfo.getDiscount();
      final int customerEnterpriseId = orderInfo.getCustomer().getCustomerEnterpriseId();
      if (isOverCreditLimit(enterpriseId, customerEnterpriseId, totalAmount)) {
        return JsonResult.createJsonResult(-100, "订单金额(" + totalAmount + ")大于可用额度");
      }
    }

    try {
      int retCode = carOrderDao.processRentalCarOrder(enterpriseId, username, orderId);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  public JsonResult finishRentalOrder(int enterpriseId, String username, int orderId, String remark) {
    RentalCarOrder order = carOrderDao.getOrderById(orderId);
    if (order.getSupplier() == null || order.getPaymentMethod() == null) {
      return JsonResult.createJsonResult(-1, "供应商、支付方式需要设置");
    }

    int retCode = 0;
    try {
      retCode = carOrderDao.finishRentalCarOrder(enterpriseId, username, orderId, remark);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }

    if (retCode == 1) {
      //TODO 导入到账单
      importService.importRentalCarOrder(enterpriseId, username, orderId);
    }

    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public void checkRentalCarOrderMeetPolicy(final int enterpriseId, final String username) {
    //只查询待处理、处理中订单
    List<RentalCarOrder> orders = carOrderDao.searchMeetPolicyRentalCarOrders(enterpriseId);

    for (RentalCarOrder o : orders) {
      //TODO 如果该订单带有乘机人信息，则根据乘机人的级别进行差旅审核；
      //如果没有，则根据订单提交的用户名来判断
      User user = userDao.getUserByUsername(o.getOperator());
      //判断是否为下级企业客户自助提交的订单
      if (user == null || user.getParentEnterprise() != enterpriseId) {
        continue;
      }

      final User mainUser = userDao.getUserById(user.getEnterpriseId());
      final int customerId = o.getCustomer().getId();

      //如果该用户没有对应的
      if (user.getPassengerId() == null) {
        //未与企业员工资料关联，无法判断哦
        carOrderDao.updateRentalCarOrderViolationStatus(enterpriseId, username, o.getId(), 0, "无相关员工资料");
        continue;
      }

      Passenger psgInfo = passengerDao.getById(user.getPassengerId());
      if (psgInfo == null) {
        //未找到该员工资料，无法判断哦
        carOrderDao.updateRentalCarOrderViolationStatus(enterpriseId, username, o.getId(), 0, "无相关员工资料");
        continue;
      }

      //当前员工的职位级别
      Integer curPositionId = psgInfo.getPosition() == null ? null : psgInfo.getPosition().getPositionId();
      if (curPositionId == null) {
        //默认使用该部门已设置的职位级别中最低的
        List<CustomerPosition> positions = enterpriseDao.searchCustomerPositions(enterpriseId, customerId);
        if (!positions.isEmpty()) {
          positions = positions.stream()
                  .sorted(Comparator.comparing(CustomerPosition::getPositionId))
                  .collect(Collectors.toList());
          curPositionId = positions.get(0).getPositionId();
        }
      }

      if (curPositionId == null) {
        //未找到该员工的职位级别，无法判断
        carOrderDao.updateRentalCarOrderViolationStatus(enterpriseId, username, o.getId(), 0, "无相关员工职级资料");
        continue;
      }

      final int positionId = curPositionId;
      //查找车型ID
      final int vehicleTypeId = o.getVehicleTypeId() == null ? 0 : o.getVehicleTypeId();
      if (vehicleTypeId == 0) {
        carOrderDao.updateRentalCarOrderViolationStatus(enterpriseId, username, o.getId(), 0, "缺少车型ID");
        continue;
      }

      //查找用车的差旅政策
      List<CustomerTpCar> tps = customerDao.searchCustomerTpCars(enterpriseId, customerId);
      tps = tps.stream()
              .filter(t -> t.getCustomerPosition().getPositionId() == positionId)
              .filter(t -> t.getVehicleGroup().getId() == vehicleTypeId)
              .collect(Collectors.toList());
      if (tps.isEmpty()) {
        carOrderDao.updateRentalCarOrderViolationStatus(enterpriseId, username, o.getId(), 0, "未找到员工职级相匹配的差旅政策");
        continue;
      }

      //默认违反，只要符合其中的一条就可以了
      int violationStatus = 1;
      String violationReason = null;
      for (CustomerTpCar tpCar : tps) {
        violationStatus = 0;
        violationReason = "符合差旅政策(" + tpCar.toString() + ")";
        break;

      }

      //TODO 应该说明符合或违法了那条政策
      carOrderDao.updateRentalCarOrderViolationStatus(enterpriseId, username, o.getId(), violationStatus, violationReason);
    }
  }

  @Override
  public void checkRentalCarOrderNeedApprover(int ownerId, String agentName) {
    List<RentalCarOrder> Orders = carOrderDao.searchNeedAssignApproverRentalOrders(ownerId);
    for (RentalCarOrder o : Orders) {
      //根据订单提交的用户名来判断
      User user = userDao.getUserByUsername(o.getOperator());
      //判断是否为下级企业客户自助提交的订单
      if (user == null || user.getParentEnterprise() != ownerId) {
        continue;
      }

      final User mainUser = userDao.getUserById(user.getEnterpriseId());
      final int customerId = o.getCustomer().getId();

      String approver = doAssignOrderApprover(ownerId, user, mainUser, customerId);
      if (approver != null) {
        assignApproverRentalOrder(ownerId, agentName, o.getId(), approver);
        //发送审批提醒
        sendCarOrderApproveAlert(ownerId, o.getOrderNo(), approver);
      }
    }
  }

  @Override
  @Secured(RoleInfo.ROLE_ADMIN)
  public JsonResult rollbackOrder(final int enterpriseId, final String username, final int orderId, final String remark) {
    if (remark == null || remark.trim().length() < 2) {
      return JsonResult.createJsonResult(-10, "请输入理由");
    }

    RentalCarOrder orderInfo = carOrderDao.getOrderById(orderId);
    if (orderInfo == null || orderInfo.getEnterpriseId() != enterpriseId) {
      return JsonResult.createJsonResult(-1, "订单不存在");
    }

    if (orderInfo.getStatus() != RENTAL_CAR_ORDER_STATUS_DONE) {
      return JsonResult.createJsonResult(-2, "订单不是完成状态。");
    }

    List<BillInfo> billInfos = billService.searchBillInfoByOrderNo(enterpriseId, orderInfo.getOrderNo());
    if (!billInfos.isEmpty()) {
      doSendAlert(enterpriseId, "订单(" + orderInfo.getOrderNo() + ")回滚失败，存在对应的账单", null, EntDepartment.DEPT_ADMINISTRATOR);
      return JsonResult.createJsonResult(-2, "存在对应的账单，不能回滚");
    }

    int retCode = carOrderDao.rollbackOrder(enterpriseId, username, orderId, remark);
    if (retCode > 0) {
      doSendAlert(enterpriseId, "租车订单(" + orderInfo.getOrderNo() + ")已回滚: " + remark, null, EntDepartment.DEPT_ADMINISTRATOR);
    }

    return JsonResult.createJsonResult(retCode);
  }

  @Override
  public JsonResult updateRentalCarOrder(int enterpriseId, String username, int orderId, int contentType, String content) {
    try {
      int retCode = carOrderDao.updateRentalCarOrder(enterpriseId, username, orderId, contentType, content);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  /**
   * 发送租车订单的审批提醒
   *
   * @param ownerId
   * @param orderNo
   * @param approver
   */
  private void sendCarOrderApproveAlert(int ownerId, String orderNo, String approver) {
    LoginInfoDto loginInfoDto = getCustomerEmployeeLoginInfo(approver, null);
    String mobile = loginInfoDto.getMobile();
    String smsContent =
            "短信内容:租车订单(" + orderNo + ")需要审批，通知指定审批人(" + approver + ").";
    String email = loginInfoDto.getEmail();
    String emailSubject = "租车订单(" + orderNo + ")等待审批";
    String emailBody = "租车订单审批邮件发送内容";
    doSendAlertApprove(ownerId, mobile, smsContent, email, emailSubject, emailBody);
  }

  private void assignApproverRentalOrder(final int enterpriseId, final String username, final int orderId,
                                         final String approver) {
//TODO 发送短信或邮件提醒该审批人
    int retCode = carOrderDao.updateRentalOrderApprover(enterpriseId, username, orderId, approver);
    if (retCode > 0) {
      //发送通知给指定的审批人
    }
  }


}
